home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / weakref.rb < prev    next >
Text File  |  2007-02-12  |  3KB  |  101 lines

  1. require "delegate"
  2.  
  3. # WeakRef is a class to represent a reference to an object that is not seen by
  4. # the tracing phase of the garbage collector.  This allows the referenced
  5. # object to be garbage collected as if nothing is referring to it. Because
  6. # WeakRef delegates method calls to the referenced object, it may be used in
  7. # place of that object, i.e. it is of the same duck type.
  8. #
  9. # Usage:
  10. #
  11. #   foo = Object.new
  12. #   foo = Object.new
  13. #   p foo.to_s            # original's class
  14. #   foo = WeakRef.new(foo)
  15. #   p foo.to_s            # should be same class
  16. #   ObjectSpace.garbage_collect
  17. #   p foo.to_s            # should raise exception (recycled)
  18. class WeakRef<Delegator
  19.  
  20.   # RefError is raised if an object cannot be referenced by a WeakRef.
  21.   class RefError<StandardError
  22.   end
  23.  
  24.   @@id_map =  {}                # obj -> [ref,...]
  25.   @@id_rev_map =  {}            # ref -> obj
  26.   @@final = lambda{|id|
  27.     __old_status = Thread.critical
  28.     Thread.critical = true
  29.     begin
  30.       rids = @@id_map[id]
  31.       if rids
  32.     for rid in rids
  33.       @@id_rev_map.delete(rid)
  34.     end
  35.     @@id_map.delete(id)
  36.       end
  37.       rid = @@id_rev_map[id]
  38.       if rid
  39.     @@id_rev_map.delete(id)
  40.     @@id_map[rid].delete(id)
  41.     @@id_map.delete(rid) if @@id_map[rid].empty?
  42.       end
  43.     ensure
  44.       Thread.critical = __old_status
  45.     end
  46.   }
  47.  
  48.   # Create a new WeakRef from +orig+.
  49.   def initialize(orig)
  50.     super
  51.     __setobj__(orig)
  52.   end
  53.  
  54.   # Return the object this WeakRef references. Raises RefError if the object
  55.   # has been garbage collected.  The object returned is the object to which
  56.   # method calls are delegated (see Delegator).
  57.   def __getobj__
  58.     unless @@id_rev_map[self.__id__] == @__id
  59.       raise RefError, "Illegal Reference - probably recycled", caller(2)
  60.     end
  61.     begin
  62.       ObjectSpace._id2ref(@__id)
  63.     rescue RangeError
  64.       raise RefError, "Illegal Reference - probably recycled", caller(2)
  65.     end
  66.   end
  67.  
  68.   def __setobj__(obj)
  69.     @__id = obj.__id__
  70.     __old_status = Thread.critical
  71.     begin
  72.       Thread.critical = true
  73.       unless @@id_rev_map.key?(self)
  74.         ObjectSpace.define_finalizer obj, @@final
  75.         ObjectSpace.define_finalizer self, @@final
  76.       end
  77.       @@id_map[@__id] = [] unless @@id_map[@__id]
  78.     ensure
  79.       Thread.critical = __old_status
  80.     end
  81.     @@id_map[@__id].push self.__id__
  82.     @@id_rev_map[self.__id__] = @__id
  83.   end
  84.  
  85.   # Returns true if the referenced object still exists, and false if it has
  86.   # been garbage collected.
  87.   def weakref_alive?
  88.     @@id_rev_map[self.__id__] == @__id
  89.   end
  90. end
  91.  
  92. if __FILE__ == $0
  93.   require 'thread'
  94.   foo = Object.new
  95.   p foo.to_s            # original's class
  96.   foo = WeakRef.new(foo)
  97.   p foo.to_s            # should be same class
  98.   ObjectSpace.garbage_collect
  99.   p foo.to_s            # should raise exception (recycled)
  100. end
  101.